package com.alan.netty.test;

import com.alan.netty.util.JsonUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author weiBin
 * @date 2018/11/6
 */
public class BeanJsonMain {
    public static void main(String[] args) {
        Bean a1 = new Bean("{\"web\":[\"2\",\"3\"],\"app\":[\"4\"]}", "1", "test1");
        Bean a2 = new Bean("{\"web\":[\"4\"],\"app\":[]}", "2", "test2");
        Bean a3 = new Bean("{\"web\":[\"4\"],\"app\":[]}", "3", "test3");
        Bean a4 = new Bean("{\"web\":[\"5\"],\"app\":[]}", "4", "test4");
        Bean b1 = new Bean("{\"web\":[],\"app\":[\"2\",\"3\"]}", "1", "test11");
        Bean b2 = new Bean("{\"web\":[],\"app\":[\"4\"]}", "2", "test22");
        Bean b3 = new Bean("{\"web\":[],\"app\":[\"4\"]}", "3", "test33");
        Bean b4 = new Bean("{\"web\":[],\"app\":[\"5\"]}", "4", "test44");
        Map<String, List<Bean>> map = new HashMap<>();
        List<Bean> webBean = new ArrayList<>();
        List<Bean> appBean = new ArrayList<>();
        webBean.add(a1);
        webBean.add(a2);
        webBean.add(a3);
        webBean.add(a4);
        appBean.add(b1);
        appBean.add(b2);
        appBean.add(b3);
        appBean.add(b4);
        map.put("web", webBean);
        map.put("app", appBean);
        reorder(map);

        List<String> ids = new ArrayList<>();
        ids.add("2");
        ids.add("3");
//        System.out.println(map.get("app").stream().filter(e->ids.contains(e.getId())).count());
    }

    private static List<Map<String, List<Bean>>> reorder(Map<String, List<Bean>> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        List<Map<String, List<Bean>>> arr = new ArrayList<>();
        List<Bean> webList = map.get("web");
        List<Bean> appList = map.get("app");
        if (webList == null) {
            webList = new ArrayList<>();
        }
        if (appList == null) {
            appList = new ArrayList<>();
        }
        int size = webList.size()+appList.size() ;
        while (webList.size() > 0 || appList.size() > 0) {
            System.out.println("------------------------------------");
            Bean temp = null;
            Map<String, List<Integer>> childIdMap = new HashMap<>();
            //类型 0 web 1 app
            int type = 0;
            if (webList.size() > 0) {
                temp = webList.get(0);
                List<Integer> childIdList = new ArrayList<>();
                childIdList.add(Integer.valueOf(temp.getId()));
                childIdMap.put("web", childIdList);
                childIdMap.put("app", new ArrayList<>());
                type = 0;
            } else if (appList.size() > 0) {
                temp = appList.get(0);
                List<Integer> childIdList = new ArrayList<>();
                childIdList.add(Integer.valueOf(temp.getId()));
                childIdMap.put("web", new ArrayList<>());
                childIdMap.put("app", childIdList);
                type = 1;
            } else {
                //没有数据了
                break;
            }
            Map<String, List<Bean>> result = getParents(temp, map, childIdMap, type);
            arr.add(result);
            remove(map, result);
        }
        for(int i = 1; i < size; i++){
            arr = sort(arr, arr.size() - 1);
        }
        while (--size>0){
            arr = sort(arr, arr.size() - 1);
        }
        for (int i = 0; i < arr.size(); i++) {
            Map<String, List<Bean>> temp = arr.get(i);
            for (String key : temp.keySet()) {
                int finalIndex = i + 1;
                temp.get(key).forEach(e -> {
                    System.out.println(String.format("index %s: type %s Bean id is %s", finalIndex, key, e.getId()));
                });
            }
        }
        return arr;
    }

    /**
     * @param bean
     * @param map
     * @param childIdMap
     * @param type
     * @return
     */
    private static Map<String, List<Bean>> getParents(Bean bean, Map<String, List<Bean>> map, Map<String, List<Integer>> childIdMap, int type) {
        Map<String, List<Bean>> result = new HashMap<>();
        //获取依赖的json
        String followIds = bean.getFollowIds();
        //为null 把当前bean添加到匹配集合中
        if (!StringUtils.isEmpty(followIds)) {
            Map object = null;
            try {
                object = JsonUtil.toObject(followIds, Map.class);
            } catch (Exception e) {
                System.err.println(e.getMessage());
                throw new RuntimeException(e.getMessage());
            }
            if (object != null && !object.isEmpty()) {
                //解析依赖的id集合
                List<String> webIds = Arrays.asList(JSONObject.parseArray(object.get("web").toString()).toArray()).stream().map(e -> String.valueOf(e)).collect(Collectors.toList());
                List<String> appIds = Arrays.asList(JSONObject.parseArray(object.get("app").toString()).toArray()).stream().map(e -> String.valueOf(e)).collect(Collectors.toList());
                for (Bean temp : map.get("web")) {
                    if (webIds.contains(temp.getId())) {
                        if (childIdMap.get("web").contains(temp.getId())) {
                            throw new RuntimeException("闭环了!");
                        }
                        childIdMap.get("web").add(Integer.valueOf(temp.getId()));
                        copy(result, getParents(temp, map, childIdMap, 0));
                        childIdMap.get("web").remove(temp.getId());
                    }
                }
                for (Bean temp : map.get("app")) {
                    if (appIds.contains(temp.getId())) {
                        if (childIdMap.get("app").contains(temp.getId())) {
                            throw new RuntimeException("闭环了!");
                        }
                        childIdMap.get("app").add(Integer.valueOf(temp.getId()));
                        copy(result, getParents(temp, map, childIdMap, 1));
                        childIdMap.get("app").remove(temp.getId());
                    }
                }
            }
        }
        if (result.size() == 0) {
            List<Bean> temp = new ArrayList<>();
            temp.add(bean);
            switch (type) {
                case 1:
                    result.put("web", new ArrayList<>());
                    result.put("app", temp);
                    break;
                case 0:
                    result.put("app", new ArrayList<>());
                    result.put("web", temp);
                    break;
                default:
                    throw new RuntimeException("type param not in [1,0]");
            }
        }
        childIdMap.keySet().forEach(k -> {
            childIdMap.get(k).forEach(item -> {
                System.out.printf(item + "->");
            });
            System.out.println();
        });
        return result;
    }

    public static Map<String, List<Bean>> copy(Map<String, List<Bean>> source, Map<String, List<Bean>> in) {
        in.keySet().forEach(key -> {
            List list = source.get(key);
            List temp = in.get(key);
            if (list != null) {
                list.addAll(temp);
            } else {
                list = temp;
            }
            HashSet h = new HashSet(list);
            list.clear();
            list.addAll(h);
            source.put(key, list);
        });
        return source;
    }

    public static Map<String, List<Bean>> remove(Map<String, List<Bean>> source, Map<String, List<Bean>> in) {
        source.keySet().forEach(key -> {
            List list = source.get(key);
            List temp = in.get(key);
            if (temp != null) {
                temp.forEach(t -> {
                    list.remove(t);
                });
            }
            source.put(key, list);
        });
        return source;
    }

    public static List<Map<String, List<Bean>>> sort(List<Map<String, List<Bean>>> list, int i) {
        if (list.size() <= i || i < 1) {
            return list;
        } else {
            Map<String, List<Bean>> map1 = list.get(i);
            Map<String, List<Bean>> map2 = list.get(i - 1);
            Map<String, List<Bean>> map3 = new ConcurrentHashMap<>();
            boolean isFlag = false;
            for (String key : map1.keySet()) {
                List<Bean> list1 = map1.get(key);
                for (Bean bean : list1) {
                    List<String> ids = Arrays.asList(JSONObject.parseArray(JsonUtil.toObject(bean.getFollowIds(), Map.class).get(key).toString()).toArray()).stream().map(e -> String.valueOf(e)).collect(Collectors.toList());
                    if (map2.get(key).stream().filter(e -> ids.contains(e.getId())).count() == 0) {
                        List<Bean> list2 = map3.get(key);
                        if (null == list2) {
                            list2 = new ArrayList<Bean>();
                        }
                        list2.add(bean);
                        map3.put(key, list2);
                    }
                }
                if (null != map3.get(key)) {
                    list1.removeAll(map3.get(key));
                    if (list1.size() > 0) {
                        isFlag = false;
                    } else {
                        isFlag = true;
                    }
                    map1.put(key, list1);
                    List<Bean> list2 = map2.get(key);
                    list2.addAll(map3.get(key));
                    map2.put(key, list2);
                } else {
                    isFlag = false;
                }
            }
            if (isFlag) {
                list.remove(i);
            }
            return sort(list, --i);
        }
    }


}

